<?php
date_default_timezone_set("Asia/Shanghai");
require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/FileTypeA.php';
require_once __DIR__ . '/Content.php';
require_once __DIR__ . '/CharacterDataHandle.php';

use Workerman\Worker;
use Workerman\Lib\Timer;
use Workerman\MySQL\Connection;

Worker::$logFile  = './transfer_result.log';
$worker = new Worker();

$config = require __DIR__ . '/config.php';
$speech3 = $config['share_path'] . $config['speech3'];
$speech4 = $config['share_path'] . $config['speech4'];
$speech_wav = $config['share_path'] . $config['speech_wav'];
$speech2 = $config['share_path'] . $config['speech2'];
$box_recording = $config['share_path'] . $config['box_recording'];

init_MergerFileAndContent();

$worker->onWorkerStart = function () {
    //循环读取队列中的数据
    Timer::add(5, function () {
        $fp = fopen(__DIR__ . "/keys/" . md5('speech_merger_running'), 'w+');
        //非阻塞
        if (!flock($fp, LOCK_EX | LOCK_NB)) {
            return;
        }
        $queue = getQueue();
        try {
            while ($id = array_pop($queue)) {
                $speech = getFileData($id);
                switch ($speech['is_manual']) {
                    case 1:
                        $file = tpyeAFileFuc($speech);
                        //文件处理
                        //0 非实时转写
                        if (!$speech['edit_state']) {
                            $content = tpyeANoNRealContentFuc($speech);
                        }
                        //1 实时转写
                        else {
                            $content = tpyeARealContentFuc($speech);
                        }

                        //角色分离
                        //$chr_content = getNonRealRoleSeparationData($id);
                        //$content = roleSeparationHandle($content, $chr_content);
                        //更新状态
                        updateSpeech($id, 2, json_encode(['list' => $content], JSON_UNESCAPED_UNICODE), $file->_length, $file->_size, $file->_fotmatname);
                        break;
                    case 2:
                        $file = tpyeBFileFuc($speech);
                        $content = tpyeBNoNRealContentFuc($speech);
                        //角色分离
                        //$chr_content = getRoleSeparationDatauseName($speech['formatname']);
                        //$content = roleSeparationHandle($content, $chr_content);
                        updateSpeech_vad($id, 2, json_encode(['list' => $content], JSON_UNESCAPED_UNICODE), $file->_length, $file->_size);
                        break;
                    default:
                        break;
                }
            }
            flock($fp, LOCK_UN);
            fclose($fp);
        } catch (\Exception $e) {
            echo $e->getMessage();
            //更新状态为失败
            updateSpeech($speech['id'], 3);
            flock($fp, LOCK_UN);
            fclose($fp);
        }
    });
};

//tpye a 的文件处理
function tpyeAFileFuc($speech)
{
    global $speech_wav,$speech2,$box_recording;
    $wavFile = $speech_wav;
    $speech2path = $speech2 . $speech['uid'] . "/";
    if(!is_dir($speech2path)){
        mkdir($speech2path, 0777, true);
    }
    $speech_list = array();
    foreach (getSpeechData($speech['id']) as $data) {
        $speech_list[] = $box_recording .  $data['formatname'];
    }
    $merger_filename = (md5(uniqid($speech['id'])));
    $filework = (new FileTypeA($wavFile . $merger_filename . ".wav"))->mergerWaves($speech_list)->waveDetailForLength()->wave2json($speech2path . $merger_filename . ".json")->wave2mp3($speech2path . $merger_filename . ".mp3");
    return $filework;
}

function handler($in_path, $out_path,$uid)
{
    AudioFileAllOperation::moveFileandTrans2Wav($in_path, $out_path);
    $seconds = AudioFileAllOperation::waveDetailLength($out_path);
    if (!is_dir(config('share_path') . config('huisheng.upload_mp3_path') . DS . $uid)) {
        mkdir(config('share_path') . config('huisheng.upload_mp3_path') . DS . $uid, 0777, true);
    }
    $mp3_path = config('share_path') . config('huisheng.upload_mp3_path') . DS . $uid . DS . pathinfo($out_path)['filename'] . ".mp3";
    AudioFileAllOperation::wavTrans2Another($out_path, $mp3_path);
    $json_path = config('share_path') . config('huisheng.upload_mp3_path') . DS . $uid . DS . pathinfo($out_path)['filename'] . ".json";
    AudioFileAllOperation::wave2json($out_path, $json_path, $seconds);
    return ['out_path' => $out_path, 'seconds' => $seconds];
}


function tpyeANoNRealContentFuc($speech)
{
    $speech_list = getSpeechData($speech['id']);
    $filecontent = new Content();
    $FRAME = 0.2;
    foreach ($speech_list as $val) {
        if (!json_decode($val['lvsr_data'], true)['list']) {
            throw new \Exception("have no transfer data");
        }
        foreach (json_decode($val['lvsr_data'], true)['list'] as $sentence) {
            $filecontent->push($sentence['txt'], number_format((explode("-", $sentence['time'])[1] - explode("-", $sentence['time'])[0]) * $FRAME, 2, '.', ''));
        }
    }
    return $filecontent->getArr();
}

function tpyeARealContentFuc($speech)
{
    $speech_list = getLiveSpeechData($speech['id']);
    $filecontent = new Content();
    foreach ($speech_list as $val) {
        $filecontent->push($val['editor'] ? $val['editor'] : $val['transfer'], $val['pcmtime'], $sc = $val['subsection']);
    }
    return $filecontent->getArr();
}
//tpye b 的文件处理
function tpyeBFileFuc($speech)
{
    global $speech3,$speech4;
    $wavFile = $speech4;
    $speech3path = $speech3 . $speech['uid'] . "/";
    $filework = (new FileTypeA($wavFile . $speech['formatname'] . ".wav"))->waveDetailForLength();
    $size = filesize($speech3path . $speech['formatname'] . ".mp3");
    $filework->_size = $size;
    return $filework;
}


//tpye b 的内容处理
function tpyeBNoNRealContentFuc($speech)
{
    $speech_list = getVadList($speech['id']);
    $filecontent = new Content();
    $FRAME = 0.2;
    foreach ($speech_list as $val) {
        $filecontent->push($val['result'], number_format(($val['etime'] - $val['stime']) * $FRAME, 2, '.', ''));
    }
    return $filecontent->getArr();
}
//
function getNonRealRoleSeparationData($id){
    global $roleSeparat;
    $lists = getSpeechData($id);
    $character_data_handel = new CharacterDataHandle();
    foreach($lists as $list){
        if(!is_file($roleSeparat . pathinfo($list['formatname'])['filename'] . ".txt")){
            return [];
        }
        $arr = file($roleSeparat . pathinfo($list['formatname'])['filename'] . ".txt");
        $character_data_handel->setCharacterArray($arr);
        //unlink($roleSeparat . pathinfo($list['formatname'])['filename'] . ".txt");
        //unlink($roleSeparat . pathinfo($list['formatname'])['filename'] . "_temp.txt");
    }
    $character_data_arr = $character_data_handel->getCharacterArray();

    return $character_data_arr;
}

//
function getRoleSeparationDatauseName($name){
    global $roleSeparat;
    if(!is_file($roleSeparat . $name . ".txt")){
        return [];
    }
    $arr = file($roleSeparat . $name . ".txt");
    $character_data_handel = new CharacterDataHandle();
    $character_data_handel->setCharacterArray($arr);
    $character_data_arr = $character_data_handel->getCharacterArray();
    //unlink($roleSeparat . $name . ".txt");
    //unlink($roleSeparat . $name . "_temp.txt");
    return $character_data_arr;
}

//添加角色分离
function roleSeparationHandle($transform_data, $cha_data){
    $i = $j = 0;
    $roleCostTimeforTrans = array();
    while($j < count($transform_data) && $i < count($cha_data)){
        $tran_stime = $transform_data[$j]['startTime'] + 0;
        $tran_etime = $transform_data[$j]['endTime'] + 0;
        $cha_stime = $cha_data[$i]['startTime'] + 0;
        $cha_etime = $cha_data[$i]['endTime'] + 0;
        $character = $cha_data[$i]['character'];
        if($cha_etime <= $tran_etime){
            if($tran_stime <= $cha_stime){
                isset($roleCostTimeforTrans[$j][$character]) ? $roleCostTimeforTrans[$j][$character] += $cha_etime - $cha_stime : $roleCostTimeforTrans[$j][$character] = $cha_etime - $cha_stime;
            }else{
                $roleCostTimeforTrans[$j][$character] = $cha_etime - $tran_stime;
            }
            if($cha_etime == $tran_etime){
                $j++;
            }
            $i++;
        }else if($cha_etime > $tran_etime){
            if($cha_stime <= $tran_stime){
                $roleCostTimeforTrans[$j][$character] = $tran_etime - $tran_stime;
            }else{
                isset($roleCostTimeforTrans[$j][$character]) ? $roleCostTimeforTrans[$j][$character] += $tran_etime - $cha_stime : $roleCostTimeforTrans[$j][$character] = $tran_etime - $cha_stime;
            }
            $j++;
        }
    }  
    $return = insertSpeakertoTransform($transform_data, $roleCostTimeforTrans);
    return  $return;               
}

function insertSpeakertoTransform($transform_data, $speaker_data){
    for($i = 0;$i < count($speaker_data); $i++){
        $speaker = compareArrayItems($speaker_data[$i]);
        $transform_data[$i]['speaker'] = $speaker ? $speaker : "未标记";
        $transform_data[$i]['sc'] = $i;
    }
    return $transform_data;
}

function compareArrayItems($array){
    $max = 0;
    $speaker = '';
    foreach($array as $key => $value){
        if($value > $max){
            $max = $value;
            $speaker = $key;
        }
    }
    return $speaker;
} 

//获取speech详细数据
function getSpeechData($id)
{
    global $mysql;
    $query = "select * from `rszh_meeting_speech` where meeting_id = $id order by filename asc";
    $result = $mysql->query($query);
    return $result;
}

//获取实时转写结果数据
function getLiveSpeechData($id)
{
    global $mysql;
    $query = "select * from `rszh_meeting_convert` where lid= $id order by sorting asc ";
    $result = $mysql->query($query);
    return $result;
}

//获取文件数据
function getFileData($id)
{
    global $mysql;
    $query = "select * from `rszh_meeting_live_speech` where id='" . $id . "'";
    $result = $mysql->query($query);
    return $result[0];
}

function updateSpeech($id, $status = 2,$content = '', $length = '', $size = 0, $formatname = '')
{
    global $mysql;
    $time = time();
    $query = "UPDATE `rszh_meeting_live_speech` SET `transfer` = '$content', `seconds` = '$length', `size` = '$size', `formatname` = '$formatname', `update_time` = '$time', `transition_state` = '$status' WHERE id = $id";
    return $mysql->query($query);
}

function updateSpeech_vad($id, $status = 2,$content = '', $length = '', $size = 0)
{
    global $mysql;
    $time = time();
    $query = "UPDATE `rszh_meeting_live_speech` SET `transfer` = '$content', `seconds` = '$length', `size` = '$size', `end_time` = '$time', `update_time` = '$time', `transition_state` = '$status' WHERE id = $id";
    return $mysql->query($query);
}

function getAllCompleteSpeechData(){
    global $mysql;
    $query = "select * from `rszh_meeting_live_speech` where transition_state in ('0','1') and is_delete = '0'";
    return $mysql->query($query);
}

//获取speech详细数据
function getMeetingSpeechData($id)
{
    global $mysql;
    $query = "select * from `rszh_meeting_speech` where meeting_id = $id order by filename desc limit 1";
    $result = $mysql->query($query);
    return $result;
}

//获取speech详细数据
function getSpeechDetailData($id)
{
    global $mysql;
    $query = "select * from `rszh_live_speech_detail` where lid = $id";
    $result = $mysql->query($query);
    return $result;
}

function updateLiveSpeech($id)
{
    global $mysql;
    $time = time();
    $query = "UPDATE `rszh_meeting_live_speech` SET  `update_time` = '$time', `transition_state` = '3' WHERE id = $id";
    return $mysql->query($query);
}

function countOfFinishVadFile($id){
    global $mysql;
    $query = "SELECT COUNT(status) AS VadCount from `rszh_speech_vad_file` where status = '1' and sid = '$id'";
    return $mysql->query($query);
}

function getVadList($id){
    global $mysql;
    $query = "select * from `rszh_speech_vad_file` where sid = '$id' order by sorting asc";
    return $mysql->query($query);
}


//初始化
function init_MergerFileAndContent()
{
    global $mysql, $redis;
    try {
        //初始化文件夹
        initdatahome_2();
        $keys_file = __DIR__ . "/keys/" . md5('speech_merger_running');
        if (!is_file($keys_file)) {
            file_put_contents($keys_file, '');
        }
        $config = require __DIR__ . '/config.php';
        //初始化mysql
        $mysql = new Connection($config['mysql']['db_host'], $config['mysql']['db_port'],  $config['mysql']['db_user'], $config['mysql']['db_pass'], $config['mysql']['db_database']);
        //初始化redis
        $redis = new Redis();
        $redis->connect($config['redis']['db_host'], $config['redis']['db_port']);
    } catch (\Exception $e) {
        exit("Init failed");
    }
}

function getQueue(){
    global $roleSeparat;
    $meetings = getAllCompleteSpeechData();
    $return = array();
    while (null != ($meeting = array_pop($meetings))) {
        if ($meeting['transition_state'] == 0 && $meeting['is_manual'] == 1) {
            //最后上传的文件的创建时间 和现在比超过 最大间隔 1小时
            $last_speech = getMeetingSpeechData($meeting['id']);
            
            //如果没有文件 就继续
            if (empty($last_speech) || (time() - $last_speech[0]['create_time']) < 3600) {
                continue;
            }
        } else if ($meeting['transition_state'] == 1 && $meeting['is_manual'] == 1) {
            //文件转写数量 和 上传数量相同
            $speech_detail = getSpeechDetailData($meeting['id']);
            $speech_data = getSpeechData($meeting['id']);
            if ($speech_detail[0]['vad_count'] == 0 || $speech_detail[0]['vad_count'] != count($speech_data)) {
                continue;
            }
        } else if ($meeting['is_manual'] == 2){
            if($meeting['is_vad'] == 0){
                continue;
            }
            $count = countOfFinishVadFile($meeting['id']);
            $vad_data = getVadList($meeting['id']);
            if($count[0]['VadCount'] != count($vad_data)){
                continue;
            }
        }
        //循环检查 转写数据的完整性
        foreach (getSpeechData($meeting['id']) as $speech) {
            if ($speech['lvsr_status'] != 3) {
                    continue 2;
                }
        }
        $return[] = $meeting['id'];
    }
    return $return;
}


function initdatahome_2()
{
    global $speech3,$speech4,$speech_wav,$speech2,$box_recording;
    $keys_dir = __DIR__ . "/keys/";
    $keys_file = __DIR__ . "/keys/" . md5('speech_merger_running');
    if (!is_dir($speech3)) {
        mkdir($speech3, 0777, true);
    }
    if (!is_dir($speech4)) {
        mkdir($speech4, 0777, true);
    }
    if (!is_dir($speech_wav)) {
        mkdir($speech_wav, 0777, true);
    }
    if (!is_dir($speech2)) {
        mkdir($speech2, 0777, true);
    }
    if (!is_dir($box_recording)) {
        mkdir($box_recording, 0777, true);
    }
    if (!is_dir($keys_dir)) {
        mkdir($keys_dir, 0777, true);
    }
    if (!is_file($keys_file)) {
        file_put_contents($keys_file, '');
    }
}

if(!defined('GLOBAL_START'))
{
    Worker::runAll();
}
